package com.allen.app.common.config.swagger;

import com.allen.app.common.config.swagger.common.ApiParamType;
import com.allen.app.common.config.swagger.common.SwaggerProperties;
import com.allen.app.common.config.swagger.reader.ApiListingReader;
import com.allen.app.common.config.swagger.reader.ApiModelFieldsReader;
import com.allen.app.common.config.swagger.reader.ApiParameterReader;
import com.allen.app.common.config.swagger.reader.ApiReaderContext;
import com.allen.app.common.utils.CheckObjectUtils;
import com.google.common.collect.Lists;
import io.swagger.annotations.ApiOperation;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.EnableScheduling;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.ApiListingBuilderPlugin;
import springfox.documentation.spi.service.OperationModelsProviderPlugin;
import springfox.documentation.spi.service.ParameterBuilderPlugin;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Slf4j
@Configuration
@EnableSwagger2
@EnableScheduling
@ConditionalOnProperty(prefix = SwaggerProperties.PREFIX, name = "enable", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(value = {SwaggerProperties.class})
public class SwaggerAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public ApiInfo apiInfo(SwaggerProperties properties) {
        log.info("\t===>>\tApiInfo initializing......");
        SwaggerProperties.Contact contact = properties.getContact();
        if (Objects.isNull(contact)) {
            contact = new SwaggerProperties.Contact();
        }
        return new ApiInfoBuilder().title(properties.getTitle()).description(properties.getDescription())
                .termsOfServiceUrl(properties.getTermsOfServiceUrl())
                .contact(new Contact(contact.getName(), contact.getUrl(), contact.getEmail()))
                .version(properties.getVersion()).license(properties.getLicense()).licenseUrl(properties.getLicenseUrl())
                .build();
    }

    @Bean
    @ConditionalOnMissingBean
    public Docket docket(ApiInfo apiInfo,SwaggerProperties properties) {
        log.info("\t===>>\tDocket initializing......");

        Docket docket = new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo).select()
            .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
            .paths(PathSelectors.any()).build()
            .pathMapping("/")
            .directModelSubstitute(LocalDate.class, String.class)
            .genericModelSubstitutes(ResponseEntity.class);

//        if(properties.isEnableSessionId()){
//            docket.globalOperationParameters(Lists.newArrayList(
//                new ParameterBuilder().name("X-SessionId").description("User Session Id")
//                    .modelRef(new ModelRef("string")).parameterType(ApiParamType.HEADER)
//                    .required(false).build()
//            ));
//            log.info("\t\t===>>\t [Swagger2]  Sessions enable, added {} parameter to be HTTP Header.", "X-SessionId");
//        }
//        if(StrUtil.isNotBlank(properties.getPagerParamType())){
//            if(Objects.equals(ApiParamType.HEADER,properties.getPagerParamType()) ||
//                Objects.equals(ApiParamType.QUERY,properties.getPagerParamType())){
//
//                docket.globalOperationParameters(Lists.newArrayList(
//                    new ParameterBuilder().name("page").description("当前页")
//                        .modelRef(new ModelRef("int")).parameterType(properties.getPagerParamType())
//                        .required(false).build(),
//                    new ParameterBuilder().name("rows").description("每页显示条数")
//                        .modelRef(new ModelRef("int")).parameterType(properties.getPagerParamType())
//                        .required(false).build(),
//                    new ParameterBuilder().name("sidx").description("排序字段,多字段\",\"分隔")
//                        .modelRef(new ModelRef("string")).parameterType(properties.getPagerParamType())
//                        .required(false).build(),
//                    new ParameterBuilder().name("sort").description("排序类型(asc or desc),多字段\",\"分隔")
//                        .modelRef(new ModelRef("string")).parameterType(properties.getPagerParamType())
//                        .required(false).build()
//                ));
//                log.info("\t\t===>>\t [Swagger2]  pagerParam enable, added {} parameter to be HTTP {}.",
//                    "[page,rows,sidx,sort]", properties.getPagerParamType());
//            }
//        }
        if(CheckObjectUtils.nonNull(properties.getHeaderParams())){
            String[] headerParamArr = properties.getHeaderParams().split(",");
            List<Parameter> list = Lists.newArrayList();
            for (String s : headerParamArr) {
                list.add(
                    new ParameterBuilder().name(s).description(s)
                        .modelRef(new ModelRef("string")).parameterType(ApiParamType.HEADER)
                        .required(false).build()
                );
            }
            docket.globalOperationParameters(list);
        }

        return docket;
    }

    @Bean
    @Scope(BeanDefinition.SCOPE_SINGLETON)
    @ConditionalOnProperty(prefix = SwaggerProperties.PREFIX, name = "use-api-hide-body-property", havingValue = "true", matchIfMissing = true)
    public ApiReaderContext apiReaderContext() {
        log.info("\t===>>\t[Swagger2] apiReaderContext initializing......");
        return new ApiReaderContext();
    }

    @Bean
    @ConditionalOnBean(ApiReaderContext.class)
    public OperationModelsProviderPlugin apiHideModelFieldsReader(ApiReaderContext context) {
        log.info("\t===>>\t[SwaggerAutoConfiguration] apiHideModelFieldsReader initializing......");
        return new ApiModelFieldsReader(context);
    }

    @Bean
    @ConditionalOnBean(ApiReaderContext.class)
    public ParameterBuilderPlugin apiHideParameterReader(ApiReaderContext context) {
        log.info("\t===>>\t[SwaggerAutoConfiguration] apiHideParameterReader initializing......");
        return new ApiParameterReader(context);
    }

    @Bean
    @ConditionalOnBean(ApiReaderContext.class)
    public ApiListingBuilderPlugin apiHideListingReader(ApiReaderContext context) {
        log.info("\t===>>\t[SwaggerAutoConfiguration] apiHideListingReader initializing......");
        return new ApiListingReader(context);
    }

}
